/**
 *
 */
package com.feizhi.common.repo;

import java.beans.PropertyDescriptor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import com.feizhi.common.ErrCode;
import com.feizhi.common.OperateResult;
import com.feizhi.common.convert.Converter;
import com.feizhi.common.convert.Transfer;
import com.feizhi.common.repo.Condition.Clause;
import com.feizhi.common.repo.Condition.Type;
import com.feizhi.common.repo.helper.ColumnNameStrategy;
import com.feizhi.common.repo.helper.SqlUtil;

/**
 * 通用的数据库操作语句, 提供对单一实体对象进行增, 删, 改, 查的操作
 *
 * @author shuaqiu 2013年11月23日
 *
 */
public class GeneralRepo {
	private static final Log log = LogFactory.getLog(GeneralRepo.class);

	private static final String ORDER_BY = " order by ";

	private NamedParameterJdbcTemplate jdbcTemplate;
	private ColumnNameStrategy columnNameStrategy;
	private SqlUtil sqlUtil;
	
	/**
     * 查询时, 如果是like 条件, 且这个值为true 时, 则会将值按照 空格 拆分成多个值<br/>
     * 比如: 值是: "会议室 预定"<br/>
     * 则会拆分成: "会议室", "预定" 这样两个值
     */
    private boolean splitLikeValue = true;

	private final Transfer<Object> nameTransfer = new ColumnNameTransfer();
	private final Transfer<Object> paramTransfer = new ColumnParamTransfer();
	private final Transfer<Object> updateTransfer = new ColumnUpdateTransfer();

	@Autowired
	public void setJdbcTemplate(final NamedParameterJdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}

	@Autowired
	public void setColumnNameStrategy(final ColumnNameStrategy columnNameStrategy) {
		this.columnNameStrategy = columnNameStrategy;
	}

	@Autowired
	public void setSqlUtil(final SqlUtil sqlUtil) {
		this.sqlUtil = sqlUtil;
	}
	
	/**
     * 查询时, 如果是like 条件, 且这个值为true 时, 则会将值按照 空格 拆分成多个值<br/>
     * 比如: 值是: "会议室 预定"<br/>
     * 则会拆分成: "会议室", "预定" 这样两个值
     */
    public void setSplitLikeValue(boolean splitLikeValue) {
        this.splitLikeValue = splitLikeValue;
    }

	/**
	 * 根据"id" 字段, 查询数据, 返回的数据是map, 适合查询的数据找不到合适的类来设置的情况.
	 *
	 * @param table
	 *            表
	 * @param id
	 *            ID 值
	 * @return 表中对应行的Map, 如果没有, 则为null.
	 */
	public Map<String, Object> queryRowMap(final String table, final int id) {
		return queryRowMap(table, "id", id);
	}

	/**
	 * 根据指定字段的值, 查询数据, 返回的数据是map, 适合查询的数据找不到合适的类来设置的情况.
	 *
	 * @param table
	 *            表
	 * @param column
	 *            字段
	 * @param value
	 *            字段值
	 * @return 表中对应行的Map, 如果没有, 则为null.
	 */
	@Transactional(readOnly = true)
	public Map<String, Object> queryRowMap(final String table, final String column, final int value) {
		final String sql = "select * from " + table + " where " + column + " = :val";
		final SqlParameterSource paramMap = new MapSqlParameterSource("val", value);

		try {
			return jdbcTemplate.queryForMap(sql, paramMap);
		} catch (final DataAccessException e) {
			log.error(e.getMessage(), e);
		}
		return null;
	}

	/**
	 * 根据指定的查询条件, 查询数据, 这个方法只能用于返回一个唯一结果的查询
	 *
	 * @param selectFrom
	 *            查询语句, 只需是select ... from ... 即可
	 * @param condition
	 *            查询条件
	 * @return 表中对应行的Map, 如果没有, 则为null.
	 */
	@Transactional(readOnly = true)
	public Map<String, Object> sqlQueryRowMap(final String selectFrom,
			final Condition condition) {
		final QueryModel queryModel = build(condition);
		final String sql = buildSelectSql(selectFrom, queryModel);

		try {
			final SqlParameterSource paramSource = queryModel.getParamSource();
			final Map<String, Object> t = jdbcTemplate.queryForMap(sql, paramSource);
			return t;
		} catch (final DataAccessException e) {
			log.error(e.getMessage(), e);
		}
		return null;
	}

	/**
	 * 根据"id" 字段, 查询数据
	 *
	 * @param table
	 *            表
	 * @param id
	 *            ID 值
	 * @param targetClass
	 *            将查询的数据转换成的实体类
	 * @return 表中对应行的实体类, 如果没有, 则为null.
	 */
	public <T> T queryRow(final String table, final int id, final Class<T> targetClass) {
		return queryRow(table, id, new BeanPropertyRowMapper<T>(targetClass));
	}

	/**
	 * 根据指定字段的值, 查询数据
	 *
	 * @param table
	 *            表
	 * @param column
	 *            字段
	 * @param value
	 *            字段值
	 * @param targetClass
	 *            将查询的数据转换成的实体类
	 * @return 表中对应行的实体类, 如果没有, 则为null.
	 */
	public <T> T queryRow(final String table, final String column, final int value,
			final Class<T> targetClass) {
		final RowMapper<T> rowMapper = new BeanPropertyRowMapper<T>(targetClass);
		return queryRow(table, column, value, rowMapper);
	}

	/**
	 * 根据"id" 字段, 查询数据
	 *
	 * @param table
	 *            表
	 * @param id
	 *            ID 值
	 * @param rowMapper
	 *            RowMapper 的实现, 定义如何将ResultSet 转换成实体类
	 * @return 表中对应行的实体类, 如果没有, 则为null.
	 */
	public <T> T queryRow(final String table, final int id, final RowMapper<T> rowMapper) {
		return queryRow(table, "id", id, rowMapper);
	}

	/**
	 * 根据指定字段的值, 查询数据
	 *
	 * @param table
	 *            表
	 * @param column
	 *            字段
	 * @param value
	 *            字段值
	 * @param rowMapper
	 *            RowMapper 的实现, 定义如何将ResultSet 转换成实体类
	 * @return 表中对应行的实体类, 如果没有, 则为null.
	 */
	@Transactional(readOnly = true)
	public <T> T queryRow(final String table, final String column, final int value,
			final RowMapper<T> rowMapper) {
		final String sql = "select * from " + table + " where " + column + " = :val";
		final SqlParameterSource paramMap = new MapSqlParameterSource("val", value);

		try {
			final T t = jdbcTemplate.queryForObject(sql, paramMap, rowMapper);
			return t;
		} catch (final DataAccessException e) {
			log.error(e.getMessage(), e);
		}
		return null;
	}

	/**
	 * 根据指定的查询条件, 查询数据, 这个方法只能用于返回一个唯一结果的查询
	 *
	 * @param table
	 *            表
	 * @param queryModel
	 *            查询条件
	 * @param rowMapper
	 *            RowMapper 的实现, 定义如何将ResultSet 转换成实体类
	 * @return 表中对应行的实体类, 如果没有, 则为null.
	 */
	@Transactional(readOnly = true)
	public <T> T queryRow(final String table, final Condition condition, final RowMapper<T> rowMapper) {
		final QueryModel queryModel = build(condition);
		final String sql = buildSelectTableSql(table, queryModel);

		try {
			final SqlParameterSource paramSource = queryModel.getParamSource();
			final T t = jdbcTemplate.queryForObject(sql, paramSource, rowMapper);
			return t;
		} catch (final DataAccessException e) {
			log.error(e.getMessage(), e);
		}
		return null;
	}

    /**
     * 根据指定的查询条件, 查询数据, 这个方法只能用于返回一个唯一结果的查询
     *
     * @param table
     *            表
     * @param queryModel
     *            查询条件
     * @param targetClass
     *            将查询的数据转换成的实体类
     * @return 表中对应行的实体类, 如果没有, 则为null.
     */
    public <T> T queryRow(final String table, final Condition condition,
            final Class<T> targetClass) {
        final RowMapper<T> rowMapper = new BeanPropertyRowMapper<T>(targetClass);
        return queryRow(table, condition, rowMapper);
    }

    /**
	 * 根据指定的查询条件, 查询数据, 这个方法只能用于返回一个唯一结果的查询
	 *
	 * @param selectFrom
	 *            查询语句, 只需是select ... from ... 即可
	 * @param queryModel
	 *            查询条件
	 * @param rowMapper
	 *            RowMapper 的实现, 定义如何将ResultSet 转换成实体类
	 * @return 表中对应行的实体类, 如果没有, 则为null.
	 */
	@Transactional(readOnly = true)
	public <T> T sqlQueryRow(final String selectFrom, final Condition condition,
			final RowMapper<T> rowMapper) {
		final QueryModel queryModel = build(condition);
		final String sql = buildSelectSql(selectFrom, queryModel);

		try {
			final SqlParameterSource paramSource = queryModel.getParamSource();
			final T t = jdbcTemplate.queryForObject(sql, paramSource, rowMapper);
			return t;
		} catch (final DataAccessException e) {
			log.error(e.getMessage(), e);
		}
		return null;
	}

	    /**
     * 根据指定的查询条件, 查询数据, 这个方法只能用于返回一个唯一结果的查询
     *
     * @param selectFrom
     *            查询语句, 只需是select ... from ... 即可
     * @param queryModel
     *            查询条件
     * @param targetClass
     *            将查询的数据转换成的实体类
     * @return 表中对应行的实体类, 如果没有, 则为null.
     */
    public <T> T sqlQueryRow(final String selectFrom, final Condition condition,
            final Class<T> targetClass) {
        final RowMapper<T> rowMapper = new BeanPropertyRowMapper<T>(targetClass);
        return sqlQueryRow(selectFrom, condition, rowMapper);
    }

    /**
	 * 查询返回唯一一个值的结果, 比如: select count(*) from table 这样的
	 *
	 * @param selectFrom
	 *            查询语句, 只需是select ... from ... 即可
	 * @param condition
	 *            条件
	 * @return 结果
	 */
	@Transactional(readOnly = true)
	public int queryInt(final String selectFrom, final Condition condition) {
		final QueryModel queryModel = build(condition);
		final String sql = buildSelectSql(selectFrom, queryModel);
		try {
			final SqlParameterSource paramSource = queryModel.getParamSource();
			return jdbcTemplate.queryForObject(sql, paramSource, Integer.class);
		} catch (final DataAccessException e) {
			log.error(e.getMessage(), e);
		}
		return 0;
	}

	/**
	 * 根据指定的查询条件, 查询数据
	 *
	 * @param table
	 *            表
	 * @param condition
	 *            查询条件
	 * @param rowMapper
	 *            RowMapper 的实现, 定义如何将ResultSet 转换成实体类
	 * @return 表中对应行的实体类, 如果查询出错, 则为null.
	 */
	@Transactional(readOnly = true)
	public <T> List<T> query(final String table, final Condition condition,
			final RowMapper<T> rowMapper) {
		final QueryModel queryModel = build(condition);
		final String sql = buildSelectTableSql(table, queryModel);

		try {
			final SqlParameterSource paramSource = queryModel.getParamSource();
			final List<T> list = jdbcTemplate.query(sql, paramSource, rowMapper);
			return list;
		} catch (final DataAccessException e) {
			log.error(e.getMessage(), e);
		}
		return null;
	}

	/**
	 * 根据指定的查询条件, 查询数据
	 *
	 * @param table
	 *            表
	 * @param condition
	 *            查询条件
	 * @param rowMapper
	 *            RowMapper 的实现, 定义如何将ResultSet 转换成实体类
	 * @return 表中对应行的实体类, 如果查询出错, 则为null.
	 */
	@Transactional(readOnly = true)
	public <T> List<T> query(final String table, final Condition condition,
			final Class<T> targetClass) {
		final RowMapper<T> rowMapper = new BeanPropertyRowMapper<T>(targetClass);
		return query(table, condition, rowMapper);
	}

	/**
	 * 根据指定的查询条件, 排序方式, 以及分页数据, 查询指定范围的数据
	 *
	 * @param table
	 *            表
	 * @param condition
	 *            查询条件
	 * @param sort
	 *            排序方式: +id,-name
	 * @param range
	 *            分页数据, 查询的数据范围: [startIndex, endIndex]
	 * @param targetClass
	 *            目标实体类
	 * @return 表中指定范围的数据, 如果查询出错, 则为null.
	 * @see #orderBy(String)
	 */
	@Transactional(readOnly = true)
	public <T> List<T> rangeQuery(final String table, final Condition condition, final String sort,
			final long[] range, final RowMapper<T> rowMapper) {

		final QueryModel queryModel = build(condition);

		final StringBuilder sql = new StringBuilder(buildSelectTableSql(table, queryModel));
        final String orderBy = orderBy(sort);
        sql.append(orderBy);

		final String rangeSql = sqlUtil.toRangeQuerySql(sql.toString(), orderBy, range);
		try {
			final SqlParameterSource paramSource = queryModel.getParamSource();
			final List<T> list = jdbcTemplate.query(rangeSql, paramSource, rowMapper);
			return list;
		} catch (final DataAccessException e) {
			log.error(e.getMessage(), e);
		}
		return null;
	}

	/**
	 * 根据指定的查询条件, 排序方式, 以及分页数据, 查询指定范围的数据
	 *
	 * @param table
	 *            表
	 * @param condition
	 *            查询条件
	 * @param sort
	 *            排序方式: +id,-name
	 * @param range
	 *            分页数据, 查询的数据范围: [startIndex, endIndex]
	 * @param targetClass
	 *            目标实体类
	 * @return 表中符合条件的数据, 如果查询出错, 则为null.
	 * @see #orderBy(String)
	 */
	public <T> List<T> rangeQuery(final String table, final Condition condition, final String sort,
			final long[] range, final Class<T> targetClass) {
		final RowMapper<T> rowMapper = new BeanPropertyRowMapper<T>(targetClass);
		return rangeQuery(table, condition, sort, range, rowMapper);
	}

	/**
	 * 构造SQL, select
	 *
	 * @param table
	 *            表
	 * @param queryModel
	 *            查询条件
	 * @return select 语句
	 */
	private String buildSelectTableSql(final String table, final QueryModel queryModel) {
		final String selectFrom = "select * from " + table;
		final String sql = buildSelectSql(selectFrom, queryModel);
		return sql;
	}

	/**
	 * 根据指定的查询条件, 查询数据
	 *
	 * @param selectFrom
	 *            表
	 * @param condition
	 *            查询条件
	 * @param rowMapper
	 *            RowMapper 的实现, 定义如何将ResultSet 转换成实体类
	 * @return 表中对应行的实体类, 如果查询出错, 则为null.
	 */
	@Transactional(readOnly = true)
	public <T> List<T> sqlQuery(final String selectFrom, final Condition condition,
			final RowMapper<T> rowMapper) {
		final QueryModel queryModel = build(condition);
		final String sql = buildSelectSql(selectFrom, queryModel);

		try {
			final SqlParameterSource paramSource = queryModel.getParamSource();
			final List<T> list = jdbcTemplate.query(sql, paramSource, rowMapper);
			return list;
		} catch (final DataAccessException e) {
			log.error(e.getMessage(), e);
		}
		return null;
	}

	/**
	 * 根据指定的查询条件, 查询数据
	 *
	 * @param selectFrom
	 *            表
	 * @param condition
	 *            查询条件
	 * @param rowMapper
	 *            RowMapper 的实现, 定义如何将ResultSet 转换成实体类
	 * @return 表中对应行的实体类, 如果查询出错, 则为null.
	 */
	@Transactional(readOnly = true)
	public <T> List<T> sqlQuery(final String selectFrom, final Condition condition,
			final Class<T> targetClass) {
		final RowMapper<T> rowMapper = new BeanPropertyRowMapper<T>(targetClass);
		return sqlQuery(selectFrom, condition, rowMapper);
	}

	/**
	 * 根据指定的查询条件, 排序方式, 查询指定范围的数据
	 *
	 * @param table
	 *            表
	 * @param condition
	 *            查询条件
	 * @param sort
	 *            排序方式: +id,-name
	 * @param targetClass
	 *            目标实体类
	 * @return 表中指定范围的数据, 如果查询出错, 则为null.
	 * @see #orderBy(String)
	 */
	@Transactional(readOnly = true)
	public <T> List<T> sqlQuery(final String selectFrom, final Condition condition,
			final String sort, final RowMapper<T> rowMapper) {

		final QueryModel queryModel = build(condition);

		final StringBuilder sql = new StringBuilder();
		sql.append(buildSelectSql(selectFrom, queryModel));
		sql.append(orderBy(sort));

		try {
			final SqlParameterSource paramSource = queryModel.getParamSource();
			final List<T> list = jdbcTemplate.query(sql.toString(), paramSource,
					rowMapper);
			return list;
		} catch (final DataAccessException e) {
			log.error(e.getMessage(), e);
		}
		return null;
	}

	/**
	 * 根据指定的查询条件, 排序方式, 查询指定范围的数据
	 *
	 * @param selectFrom
	 *            select ... from ... 语句, 不需带where
	 * @param condition
	 *            查询条件
	 * @param sort
	 *            排序方式: +id,-name
	 * @param targetClass
	 *            目标实体类
	 * @return 表中符合条件的数据, 如果查询出错, 则为null.
	 * @see #orderBy(String)
	 */
	public <T> List<T> sqlQuery(final String selectFrom, final Condition condition,
			final String sort, final Class<T> targetClass) {
		final RowMapper<T> rowMapper = new BeanPropertyRowMapper<T>(targetClass);
		return sqlQuery(selectFrom, condition, sort, rowMapper);
	}

	/**
	 * 根据指定的查询条件, 排序方式, 以及分页数据, 查询指定范围的数据
	 *
	 * @param table
	 *            表
	 * @param condition
	 *            查询条件
	 * @param sort
	 *            排序方式: +id,-name
	 * @param range
	 *            分页数据, 查询的数据范围: [startIndex, endIndex]
	 * @param targetClass
	 *            目标实体类
	 * @return 表中指定范围的数据, 如果查询出错, 则为null.
	 * @see #orderBy(String)
	 */
	@Transactional(readOnly = true)
	public <T> List<T> rangeSqlQuery(final String selectFrom, final Condition condition,
			final String sort, final long[] range, final RowMapper<T> rowMapper) {

		final QueryModel queryModel = build(condition);

		final StringBuilder sql = new StringBuilder();
        final String orderBy = orderBy(sort);

		sql.append(buildSelectSql(selectFrom, queryModel));
        sql.append(orderBy);

		final String rangeSql = sqlUtil.toRangeQuerySql(sql.toString(), orderBy, range);
		try {
			final SqlParameterSource paramSource = queryModel.getParamSource();
			log.debug(sql);
			log.debug(paramSource);
			final List<T> list = jdbcTemplate.query(rangeSql, paramSource, rowMapper);
			return list;
		} catch (final DataAccessException e) {
			log.error(e.getMessage(), e);
		}
		return null;
	}

	/**
	 * 根据指定的查询条件, 排序方式, 以及分页数据, 查询指定范围的数据
	 *
	 * @param selectFrom
	 *            select ... from ... 语句, 不需带where
	 * @param condition
	 *            查询条件
	 * @param sort
	 *            排序方式: +id,-name
	 * @param range
	 *            分页数据, 查询的数据范围: [startIndex, endIndex]
	 * @param targetClass
	 *            目标实体类
	 * @return 表中符合条件的数据, 如果查询出错, 则为null.
	 * @see #orderBy(String)
	 */
	public <T> List<T> rangeSqlQuery(final String selectFrom, final Condition condition,
			final String sort, final long[] range, final Class<T> targetClass) {
		final RowMapper<T> rowMapper = new BeanPropertyRowMapper<T>(targetClass);
		return rangeSqlQuery(selectFrom, condition, sort, range, rowMapper);
	}

	/**
	 * 构造SQL, select
	 *
	 * @param selectFrom
	 *            select ... from ... 语句, 不需带where
	 * @param queryModel
	 *            查询条件
	 * @return select 语句
	 */
	private String buildSelectSql(final String selectFrom,
			final QueryModel queryModel) {

		final StringBuilder sql = new StringBuilder(selectFrom);

		if (queryModel != null && StringUtils.hasText(queryModel.getSql())) {
			sql .append(" where " + queryModel.getSql());
		}
		return sql.toString();
	}

	/**
	 * 查询表中符合条件的记录数量
	 *
	 * @param table
	 *            表
	 * @param condition
	 *            查询条件
	 * @return 记录数量
	 */
	public long count(final String table, final Condition condition) {
		final String selectFrom = "select count(*) from " + table;

		final QueryModel queryModel = build(condition);
		final String sql = buildSelectSql(selectFrom, queryModel);

		try {
			final SqlParameterSource paramSource = queryModel.getParamSource();
			final long count = jdbcTemplate.queryForObject(sql, paramSource,
					Long.class);
			return count;
		} catch (final DataAccessException e) {
			log.error(e.getMessage(), e);
		}
		return 0;
	}

	/**
	 * 处理排序字段: 将"+id,-name" 这样格式的字符串, 转换成正确的SQL 排序语句
	 *
	 * @param sort
	 *            "+id,-name" 格式的字符串, 其中: "+" 号或" "(空格) 表示升序, "-" 表示降序.
	 * @return SQL 排序语句: order by id, name desc
	 */
	public String orderBy(final String sort) {
		if (!StringUtils.hasText(sort) || sort.length() <= 1) {
			return "";
		}
		final String[] arr = sort.split(",");

		final List<String> orderby = new ArrayList<String>(arr.length);
		for (final String str : arr) {
			if (StringUtils.hasText(str) && str.length() > 1) {
				final String prop = str.substring(1);
				final String columnName = columnNameStrategy.getColumnName(prop);

				if (str.startsWith("+") || str.startsWith(" ")) {
					orderby.add(columnName);
				} else if (str.startsWith("-")) {
					orderby.add(columnName + " desc");
				}
			}
		}
		return ORDER_BY + StringUtils.collectionToCommaDelimitedString(orderby);
	}

	private QueryModel build(final Condition condition) {
		final String table = null;
		return build(table, condition);
	}

	/**
	 * @param table
	 * @param condition
	 * @return
	 */
	private QueryModel build(final String table, final Condition condition) {
		if (condition == null || condition.isEmpty()) {
			return new QueryModel("", null);
		}

		final StringBuilder sql = new StringBuilder();
		final MapSqlParameterSource paramSource = new MapSqlParameterSource();

		final List<Clause> clauses = condition.getClauses();

		int index = 0;
		for (final Clause clause : clauses) {
			if (index > 0) {
				sql.append(" and ");
			}

			final String[] props = clause.getProps();
            final String paramName = buildParamName(props, index);
            final Type type = clause.getType();

            if (type == Type.IN || type == Type.NOT_IN) {
                final Collection<?> value = (Collection<?>) clause.getValue();
                if (value == null || value.size() == 0) {
                    index++;
                    continue;
                }

                final StringBuilder in = new StringBuilder("(");
                int i = 0;
                for (final Object val : value) {
                    final String inParamName = paramName + "_" + i;
                    paramSource.addValue(inParamName, val);

                    if(i > 0){
                        in.append(", ");
                    }
                    in.append(" :" + inParamName);
                    i++;
                }
                in.append(" )");

                sql.append("(");
                sql.append(buildSql(table, props, in.toString(), type));
                sql.append(")");
            } else if (splitLikeValue && (type == Type.LIKE || type == Type.NOT_LIKE)) {
                final String value = (String) clause.getValue();
                if (value == null || value.trim().equals("")) {
                    continue;
                }
                final String[] values = value.split(" ");

                final StringBuilder like = new StringBuilder("(");
                int i = 0;
                for (final String val : values) {
                    final String likeParamName = paramName + "_" + i;
                    paramSource.addValue(likeParamName, buildLikeValue(val));

                    if (i > 0) {
                        like.append(" or ");
                    }

                    like.append(buildSql(table, props, ":" + likeParamName, type));
                    i++;
                }
                like.append(" )");

                sql.append("(");
                sql.append(like.toString());
                sql.append(")");
            } else {
                paramSource.addValue(paramName, buildValue(clause));
                
                sql.append("(");
                sql.append(buildSql(table, props, ":" + paramName, type));
                sql.append(")");
            }

			index++;
		}

        final List<String> custom = condition.getCustom();
        if (custom != null && custom.size() > 0) {
            for (final String cond : custom) {
                if (index > 0) {
                    sql.append(" and ");
                }
                sql.append(cond);
                index++;
            }
        }

		if (condition.getCustomParam() != null) {
			paramSource.addValues(condition.getCustomParam());
		}

		return new QueryModel(sql.toString(), paramSource);
	}

    /**
     * @param table
     *            表
     * @param props
     *            属性值
     * @param paramNames
     *            参数名称, 需要带上冒号(:), 例如: <code>:value</code><br/>
     *            对于in/ not in, 则是在in/ not in 后面的表达式(包括括号), 例如: <code>(:value_1, :value_2, ...)</code>
     * @param type
     *            类型
     * @return
     */
    private String buildSql(final String table, final String[] props, final String paramNames, final Type type) {
        final StringBuilder sql = new StringBuilder();

        boolean isFirst = true;
        for (final String prop : props) {
            if (isFirst) {
                isFirst = false;
            } else {
                sql.append(" or ");
            }
            sql.append(buildColumn(table, prop));
            sql.append(" " + type.getOperator());
            sql.append(" " + paramNames);

        }

        return sql.toString();
    }

    /**
	 * @param table
	 * @param prop
	 * @return
	 */
	private String buildColumn(final String table, final String prop) {
		final StringBuilder col = new StringBuilder();
		if (StringUtils.hasText(table)) {
			col.append(table);
			col.append(".");
		}
		col.append(columnNameStrategy.getColumnName(prop));
		return col.toString();
	}

	/**
	 * @param props
	 * @param index
	 * @return
	 */
	private String buildParamName(final String[] props, final int index) {
		return StringUtils.arrayToDelimitedString(props, "_") + "_" + index;
	}

	/**
	 * @param clause
	 * @return
	 */
	private Object buildValue(final Clause clause) {
		final Object value = clause.getValue();
		final Type type = clause.getType();
		if (type == Type.LIKE || type == Type.NOT_LIKE) {
			return buildLikeValue(value.toString());
		}
		return value;
	}

    /**
     * @param val
     * @return
     */
    private Object buildLikeValue(String val) {
        return "%" + sqlUtil.escapeLikeValue(val) + "%";
    }

	/**
	 * 执行指定的SQL, 这里的SQL 可以是insert, update, delete.
	 *
	 * <pre>
	 * <ul><li>如果执行成功, 则返回的{@link OperateResult } 为: {
	 *     isOK : true,
	 *     obj : SQL 执行影响的记录数
	 * }</li><li>如果执行失败, 则返回的{@link OperateResult } 为: {
	 *     isOK : false,
	 *     message : 异常信息(e.getMessage())
	 * }</li><ul>
	 * </pre>
	 *
	 * @param sql
	 *            SQL, 可以是insert, update, delete.
	 * @param paramSource
	 *            SQL 中的参数值
	 * @return
	 * @author qiushaohua 2012-4-4
	 */
	@Transactional
	public OperateResult executeUpdate(final String sql,
			final SqlParameterSource paramSource) {
		try {
			final int updated = jdbcTemplate.update(sql, paramSource);
			return new OperateResult(true, updated);
		} catch (final DataAccessException e) {
			log.error(e.getMessage(), e);
			return new OperateResult(ErrCode.EXCEPTION, e.getMessage());
		}
	}

	/**
	 * 执行指定的SQL, 这里的SQL 可以是insert, update, delete.
	 *
	 * <pre>
	 * <ul><li>如果执行成功, 则返回的{@link OperateResult } 为: {
	 *     isOK : true,
	 *     obj : SQL 执行影响的记录数
	 * }</li><li>如果执行失败, 则返回的{@link OperateResult } 为: {
	 *     isOK : false,
	 *     message : 异常信息(e.getMessage())
	 * }</li><ul>
	 * </pre>
	 *
	 * @param sql
	 *            SQL, 可以是insert, update, delete.
	 * @param paramMap
	 *            SQL 中的参数值
	 * @return 执行结果
	 * @author qiushaohua 2012-4-4
	 */
	public OperateResult executeUpdate(final String sql, final Map<String, ?> paramMap) {
		final SqlParameterSource paramSource = new MapSqlParameterSource(paramMap);
		return executeUpdate(sql, paramSource);
	}

	/**
	 * 根据"id" 字段, 删除表中的数据
	 *
	 * <pre>
	 * <ul><li>如果执行成功, 则返回的{@link OperateResult } 为: {
	 *     isOK : true,
	 *     obj : SQL 执行影响的记录数
	 * }</li><li>如果执行失败, 则返回的{@link OperateResult } 为: {
	 *     isOK : false,
	 *     message : 异常信息(e.getMessage())
	 * }</li><ul>
	 * </pre>
	 *
	 * @param table
	 *            表
	 * @param id
	 *            ID 值
	 * @return 删除结果
	 */
	public OperateResult delete(final String table, final int id) {
		return delete(table, "id", id);
	}

	/**
	 * 删除表中指定的数据
	 *
	 * <pre>
	 * <ul><li>如果执行成功, 则返回的{@link OperateResult } 为: {
	 *     isOK : true,
	 *     obj : SQL 执行影响的记录数
	 * }</li><li>如果执行失败, 则返回的{@link OperateResult } 为: {
	 *     isOK : false,
	 *     message : 异常信息(e.getMessage())
	 * }</li><ul>
	 * </pre>
	 *
	 * @param table
	 *            表
	 * @param column
	 *            字段
	 * @param value
	 *            字段值
	 * @return 删除结果
	 */
	public OperateResult delete(final String table, final String column, final int value) {
		final String sql = "delete from " + table + " where " + column + " = :val";
		final SqlParameterSource paramMap = new MapSqlParameterSource("val", value);

		return executeUpdate(sql, paramMap);
	}

	/**
	 * 删除表中指定的数据
	 *
	 * <pre>
	 * <ul><li>如果执行成功, 则返回的{@link OperateResult } 为: {
	 *     isOK : true,
	 *     obj : SQL 执行影响的记录数
	 * }</li><li>如果执行失败, 则返回的{@link OperateResult } 为: {
	 *     isOK : false,
	 *     message : 异常信息(e.getMessage())
	 * }</li><ul>
	 * </pre>
	 *
	 * @param table
	 *            表
	 * @param condition
	 *            条件
	 * @return 删除结果
	 */
	public OperateResult delete(final String table, final Condition condition) {
		final QueryModel queryModel = build(condition);
		final String sql = buildSelectSql("delete from " + table, queryModel);
		return executeUpdate(sql, queryModel.getParamSource());
	}

	/**
	 * 执行insert 操作
	 *
	 * <pre>
	 * <ul><li>如果执行成功, 则返回的{@link OperateResult } 为: {
	 *     isOK : true,
	 *     obj : 参数中的generatedKeyHolder
	 * }</li><li>如果执行失败, 则返回的{@link OperateResult } 为: {
	 *     isOK : false,
	 *     message : 异常信息(e.getMessage())
	 * }</li><ul>
	 * </pre>
	 *
	 * @param sql
	 *            SQL insert
	 * @param paramSource
	 *            SQL 中的参数值
	 * @param generatedKeyHolder
	 *            KeyHolder, 用来保存生成的主键
	 * @return 执行结果
	 * @author qiushaohua 2012-5-2
	 */
	@Transactional
	public OperateResult sqlInsert(final String sql, final SqlParameterSource paramSource,
			final KeyHolder generatedKeyHolder) {
		try {
			jdbcTemplate.update(sql, paramSource, generatedKeyHolder);
			return new OperateResult(true, generatedKeyHolder);
		} catch (final DataAccessException e) {
			log.error(e.getMessage(), e);
			return new OperateResult(ErrCode.EXCEPTION, e.getMessage());
		}
	}

	/**
	 * 执行insert 操作
	 *
	 * <pre>
	 * <ul><li>如果执行成功, 则返回的{@link OperateResult } 为: {
	 *     isOK : true,
	 *     obj : 参数中的generatedKeyHolder
	 * }</li><li>如果执行失败, 则返回的{@link OperateResult } 为: {
	 *     isOK : false,
	 *     message : 异常信息(e.getMessage())
	 * }</li><ul>
	 * </pre>
	 *
	 * @param sql
	 *            SQL insert
	 * @param paramMap
	 *            SQL 中的参数值
	 * @param generatedKeyHolder
	 *            KeyHolder, 用来保存生成的主键
	 * @return 执行结果
	 * @author qiushaohua 2012-5-2
	 */
	public OperateResult sqlInsert(final String sql, final Map<String, ?> paramMap,
			final KeyHolder generatedKeyHolder) {
		final SqlParameterSource paramSource = new MapSqlParameterSource(paramMap);
		return sqlInsert(sql, paramSource, generatedKeyHolder);
	}

	/**
	 * 执行insert 操作, 其中"id" 属性不进行插入(适用于id 是自增的情况)
	 *
	 * 执行结果为:
	 *
	 * <pre>
	 * <ul><li>如果执行成功, 则返回的{@link OperateResult } 为: {
	 *     isOK : true,
	 *     obj : generatedKeyHolder, 可以获取生成的id 字段的值
	 * }</li><li>如果执行失败, 则返回的{@link OperateResult } 为: {
	 *     isOK : false,
	 *     message : 异常信息(e.getMessage())
	 * }</li><ul>
	 * </pre>
	 *
	 * @param table
	 *            表
	 * @param t
	 *            实体对象
	 * @param ignores
	 *            要忽略的属性列表(需要注意这个是实体类中的属性, 不是数据库字段), 这些属性不做插入
	 * @return update 结果
	 */
	public <T> OperateResult insert(final String table, final T t, final String... ignores) {
		final String sql = buildInsertSql(table, t.getClass(),
				buildIgnores("id", ignores));
		final SqlParameterSource paramSource = new BeanPropertySqlParameterSource(t);
		final KeyHolder generatedKeyHolder = new GeneratedKeyHolder();
		final OperateResult result = sqlInsert(sql, paramSource, generatedKeyHolder);
		return result;
	}

	/**
	 * 执行insert 操作, 所有属性进行插入(适用于id 不是自增的情况)
	 *
	 * 执行结果为:
	 * <pre>
	 * <ul><li>如果执行成功, 则返回的{@link OperateResult } 为: {
	 *     isOK : true,
	 *     obj : SQL 执行影响的记录数
	 * }</li><li>如果执行失败, 则返回的{@link OperateResult } 为: {
	 *     isOK : false,
	 *     message : 异常信息(e.getMessage())
	 * }</li><ul>
	 * </pre>
	 *
	 * @param table
	 *            表
	 * @param t
	 *            实体对象
	 * @return update 结果
	 */
	public <T> OperateResult insertWithId(final String table, final T t) {
		return insertIgnore(table, t);
	}

	/**
	 * 执行insert 操作, 其中在ignores 中的属性不进行插入(需注意和
	 * {@link #insert(String, Object, String...) } 方法的区别, 这个方法不返回生成的key,
	 * 而是返回插入的记录数, 因为这个方法不能确定哪个字段是key). <br/>
	 *
	 * 执行结果为:
	 *
	 * <pre>
	 * <ul><li>如果执行成功, 则返回的{@link OperateResult } 为: {
	 *     isOK : true,
	 *     obj : SQL 执行影响的记录数
	 * }</li><li>如果执行失败, 则返回的{@link OperateResult } 为: {
	 *     isOK : false,
	 *     message : 异常信息(e.getMessage())
	 * }</li><ul>
	 * </pre>
	 *
	 * @param table
	 *            表
	 * @param t
	 *            实体对象
	 * @param ignores
	 *            要忽略的属性列表(需要注意这个是实体类中的属性, 不是数据库字段), 这些属性不做插入
	 * @return update 结果
	 */
	@Transactional
	public <T> OperateResult insertIgnore(final String table, final T t,
			final String... ignores) {
		final String sql = buildInsertSql(table, t.getClass(), ignores);
		final SqlParameterSource paramSource = new BeanPropertySqlParameterSource(t);
		final OperateResult result = executeUpdate(sql, paramSource);
		return result;
	}

	/**
	 * 批量执行insert 操作, 其中"id" 属性不进行插入(适用于id 是自增的情况)
	 *
	 * 执行结果为:
	 *
	 * <pre>
	 * <ul><li>如果列表为空(null or size == 0), 则返回的{@link OperateResult } 为: {
	 *     isOK : false,
	 *     errCode : ErrCode.NULL,
	 *     message : "not record to insert"
	 * }</li><li>如果执行成功, 则返回的{@link OperateResult } 为: {
	 *     isOK : true,
	 *     obj : SQL 执行影响的记录数
	 * }</li><li>如果执行失败, 则返回的{@link OperateResult } 为: {
	 *     isOK : false,
	 *     message : 异常信息(e.getMessage())
	 * }</li><ul>
	 * </pre>
	 *
	 * @param table
	 *            表
	 * @param list
	 *            实体对象列表, 要求所有的元素都是同一个类的实体(如果有些是子类, 则有可能引起错误)
	 * @param ignores
	 *            除id 字段之外, 还需要忽略的属性列表(需要注意这个是实体类中的属性, 不是数据库字段), 这些属性不做插入.
	 * @return insert 结果
	 */
	public <T> OperateResult batchInsert(final String table, final List<T> list,
			final String... ignores) {
		if (list == null || list.size() == 0) {
			return new OperateResult(ErrCode.NULL, "not record to insert");
		}
		return batchInsertIgnore(table, list, buildIgnores("id", ignores));
	}

	/**
	 * 批量执行insert 操作, 所有属性进行插入(适用于id 不是自增的情况), 如果有属性需要忽略, 则请使用
	 * {@link #batchInsertIgnore(String, List, String...)} <br/>
	 *
	 * 执行结果为:
	 *
	 * <pre>
	 * <ul><li>如果列表为空(null or size == 0), 则返回的{@link OperateResult } 为: {
	 *     isOK : false,
	 *     errCode : ErrCode.NULL,
	 *     message : "not record to insert"
	 * }</li><li>如果执行成功, 则返回的{@link OperateResult } 为: {
	 *     isOK : true,
	 *     obj : SQL 执行影响的记录数
	 * }</li><li>如果执行失败, 则返回的{@link OperateResult } 为: {
	 *     isOK : false,
	 *     message : 异常信息(e.getMessage())
	 * }</li><ul>
	 * </pre>
	 *
	 * @param table
	 *            表
	 * @param list
	 *            实体对象列表, 要求所有的元素都是同一个类的实体(如果有些是子类, 则有可能引起错误)
	 * @return update 结果
	 */
	public <T> OperateResult batchInsertWithId(final String table, final List<T> list) {
		return batchInsertIgnore(table, list);
	}

	/**
	 * 批量执行insert 操作, 其中在ignores 中的属性不进行插入. <br/>
	 *
	 * 执行结果为:
	 *
	 * <pre>
	 * <ul><li>如果列表为空(null or size == 0), 则返回的{@link OperateResult } 为: {
	 *     isOK : false,
	 *     errCode : ErrCode.NULL,
	 *     message : "not record to insert"
	 * }</li><li>如果执行成功, 则返回的{@link OperateResult } 为: {
	 *     isOK : true,
	 *     obj : SQL 执行影响的记录数
	 * }</li><li>如果执行失败, 则返回的{@link OperateResult } 为: {
	 *     isOK : false,
	 *     message : 异常信息(e.getMessage())
	 * }</li><ul>
	 * </pre>
	 *
	 * @param table
	 *            表
	 * @param list
	 *            实体对象列表, 要求所有的元素都是同一个类的实体(如果有些是子类, 则有可能引起错误)
	 * @param ignores
	 *            要忽略的属性列表(需要注意这个是实体类中的属性, 不是数据库字段), 这些属性不做插入
	 * @return update 结果
	 */
	@Transactional
	public <T> OperateResult batchInsertIgnore(final String table, final List<T> list,
			final String... ignores) {
		if (list == null || list.size() == 0) {
			return new OperateResult(ErrCode.NULL, "not record to insert");
		}
		final Class<? extends Object> clazz = list.get(0).getClass();
		final String sql = buildInsertSql(table, clazz, ignores);

		final int size = list.size();

		final SqlParameterSource[] batchArgs = new SqlParameterSource[size];
		for (int i = 0; i < size; i++) {
			final T t = list.get(i);
			batchArgs[i] = new BeanPropertySqlParameterSource(t);
		}

		try {
			final int[] result = jdbcTemplate.batchUpdate(sql, batchArgs);
			return new OperateResult(true, result);
		} catch (final Exception e) {
			log.error(e.getMessage(), e);
			return new OperateResult(ErrCode.EXCEPTION, e.getMessage());
		}
	}

	/**
	 * 构造insert 语句
	 *
	 * @param table
	 *            表
	 * @param t
	 *            实体对象
	 * @param ignores
	 *            要忽略的属性列表(需要注意这个是实体类中的属性, 不是数据库字段), 这些属性不做插入
	 * @return insert 语句
	 */
	private String buildInsertSql(final String table, final Class<?> clazz,
			final String... ignores) {

		final String[] propNames = getPropNames(clazz, ignores);
		if (propNames == null || propNames.length == 0) {
			throw new IllegalArgumentException("It's not a Plain Object: "
					+ clazz.getName());
		}

		final StringBuilder sql = new StringBuilder("insert into ");
		sql.append(table);
		sql.append(" ( ");
		sql.append(Converter.arrayToString(propNames, ", ", nameTransfer));
		sql.append(") values (");
		sql.append(Converter.arrayToString(propNames, ", ", paramTransfer));
		sql.append(") ");
		return sql.toString();
	}

	/**
	 * 执行update 操作, 根据"id" 属性进行更新.
	 *
	 * 执行结果为:
	 *
	 * <pre>
	 * <ul><li>如果执行成功, 则返回的{@link OperateResult } 为: {
	 *     isOK : true,
	 *     obj : SQL 执行影响的记录数
	 * }</li><li>如果执行失败, 则返回的{@link OperateResult } 为: {
	 *     isOK : false,
	 *     message : 异常信息(e.getMessage())
	 * }</li><ul>
	 * </pre>
	 *
	 * @param table
	 *            表
	 * @param t
	 *            实体对象
	 * @return update 结果
	 */
	public <T> OperateResult update(final String table, final T t) {
		return updateByKey(table, t, "id");
	}

	/**
	 * 执行update 操作, 根据"id" 属性进行更新.
	 *
	 * 执行结果为:
	 *
	 * <pre>
	 * <ul><li>如果执行成功, 则返回的{@link OperateResult } 为: {
	 *     isOK : true,
	 *     obj : SQL 执行影响的记录数
	 * }</li><li>如果执行失败, 则返回的{@link OperateResult } 为: {
	 *     isOK : false,
	 *     message : 异常信息(e.getMessage())
	 * }</li><ul>
	 * </pre>
	 *
	 * @param table
	 *            表
	 * @param t
	 *            实体对象
	 * @param ignores
	 *            要忽略的属性列表(需要注意这个是实体类中的属性, 不是数据库字段), 这些属性不做更新
	 * @return update 结果
	 */
	public <T> OperateResult updateIgnore(final String table, final T t, final String... ignores) {
		return updateByKeyIgnore(table, t, "id", ignores);
	}

	/**
	 * 执行update 操作
	 * <p>
	 * 这里只支持单一主键的情况, 如果是多主键, 则自己构造SQL 执行来
	 * {@link #executeUpdate(String, SqlParameterSource)} 或
	 * {@link #executeUpdate(String, Map)} 方法更合适
	 * </p>
	 *
	 * 执行结果为:
	 *
	 * <pre>
	 * <ul><li>如果执行成功, 则返回的{@link OperateResult } 为: {
	 *     isOK : true,
	 *     obj : SQL 执行影响的记录数
	 * }</li><li>如果执行失败, 则返回的{@link OperateResult } 为: {
	 *     isOK : false,
	 *     message : 异常信息(e.getMessage())
	 * }</li><ul>
	 * </pre>
	 *
	 * @param table
	 *            表
	 * @param t
	 *            实体对象
	 * @param keyProp
	 *            主键属性(需要注意这个是实体类中的属性, 不是数据库字段) <br/>
	 *            update 语句的where 条件为: keyColumn = :keyProp
	 * @return update 结果
	 */
	public <T> OperateResult updateByKey(final String table, final T t, final String keyProp) {
		return updateByKeyIgnore(table, t, keyProp);
	}

	/**
	 * 执行update 操作
	 * <p>
	 * 这里只支持单一主键的情况, 如果是多主键, 则自己构造SQL 执行来
	 * {@link #executeUpdate(String, SqlParameterSource)} 或
	 * {@link #executeUpdate(String, Map)} 方法更合适
	 * </p>
	 *
	 * 执行结果为:
	 *
	 * <pre>
	 * <ul><li>如果执行成功, 则返回的{@link OperateResult } 为: {
	 *     isOK : true,
	 *     obj : SQL 执行影响的记录数
	 * }</li><li>如果执行失败, 则返回的{@link OperateResult } 为: {
	 *     isOK : false,
	 *     message : 异常信息(e.getMessage())
	 * }</li><ul>
	 * </pre>
	 *
	 * @param table
	 *            表
	 * @param t
	 *            实体对象
	 * @param keyProp
	 *            主键属性(需要注意这个是实体类中的属性, 不是数据库字段) <br/>
	 *            update 语句的where 条件为: keyColumn = :keyProp
	 * @param ignores
	 *            要忽略的属性列表(需要注意这个是实体类中的属性, 不是数据库字段), 这些属性不做更新
	 * @return update 结果
	 */
	public <T> OperateResult updateByKeyIgnore(final String table, final T t, final String keyProp,
			final String... ignores) {
		final String sql = buildUpdateSql(table, t.getClass(), keyProp, ignores);
		final SqlParameterSource paramSource = new BeanPropertySqlParameterSource(t);
		final OperateResult result = executeUpdate(sql, paramSource);
		return result;
	}

	/**
	 * 构造update 语句
	 * <p>
	 * 这里只支持单一主键的情况, 如果是多主键, 则自己构造SQL 执行来
	 * {@link #executeUpdate(String, SqlParameterSource)} 或
	 * {@link #executeUpdate(String, Map)} 方法更合适
	 * </p>
	 *
	 * @param table
	 *            表
	 * @param t
	 *            实体对象
	 * @param keyProp
	 *            主键属性(需要注意这个是实体类中的属性, 不是数据库字段) <br/>
	 *            update 语句的where 条件为: keyColumn = :keyProp <br/>
	 *            另外, keyProp 不会再出现在update 的set 列表中
	 * @param ignores
	 *            要忽略的属性列表
	 * @return update 语句
	 */
	private String buildUpdateSql(final String table, final Class<?> clazz, final String keyProp,
			String... ignores) {
		ignores = buildIgnores(keyProp, ignores);
		final String[] propNames = getPropNames(clazz, ignores);
		if (propNames == null || propNames.length == 0) {
			throw new IllegalArgumentException("It's not a Plain Object: "
					+ clazz.getName());
		}

		final StringBuilder sql = new StringBuilder("update ");
		sql.append(table);
		sql.append(" set ");
		sql.append(Converter.arrayToString(propNames, ", ", updateTransfer));
		sql.append(" where " + updateTransfer.transfer(keyProp));
		return sql.toString();
	}

	/**
	 * 将主键属性和要忽略的属性列表, 合并成一个新的忽略属性列表
	 *
	 * @param keyProp
	 *            主键属性
	 * @param ignores
	 *            要忽略的属性列表
	 * @return 合并的新的忽略属性列表
	 */
	private String[] buildIgnores(final String keyProp, final String... ignores) {
		if (keyProp == null) {
			return ignores;
		}
		if (ignores == null || ignores.length == 0) {
			return new String[] { keyProp };
		}
		final List<String> list = new ArrayList<String>(ignores.length + 1);
		list.add(keyProp);
		list.addAll(Arrays.asList(ignores));
		return list.toArray(new String[list.size()]);
	}

	/**
	 * 获取实体类中的属性名称列表
	 *
	 * @param clazz
	 *            实体类
	 * @param ignores
	 *            要忽略的属性列表
	 * @return 实体类中的属性名称列表, 排除要忽略的那些
	 */
	private String[] getPropNames(final Class<?> clazz, final String... ignores) {
		final PropertyDescriptor[] props = BeanUtils.getPropertyDescriptors(clazz);

		final List<String> names = new ArrayList<String>(props.length);
		for (final PropertyDescriptor prop : props) {
			if (isIgnore(prop, ignores)) {
				continue;
			}
			names.add(prop.getName());
		}
		return names.toArray(new String[names.size()]);
	}

	/**
	 * 判断属性是否在忽略列表中, 注意, "class" 这个是直接忽略的.
	 *
	 * @param prop
	 *            属性
	 * @param ignores
	 *            要忽略的字段列表
	 * @return 属性是否在忽略列表中
	 */
	private boolean isIgnore(final PropertyDescriptor prop, final String... ignores) {
		final String name = prop.getName();
		if ("class".equals(name) || ignores == null || ignores.length == 0) {
			return true;
		}
		for (final String key : ignores) {
			if (key.equals(name)) {
				return true;
			}
		}
		return false;
	}

	/** column --> 根据配置的字段规则, 将bean 属性转换成数据库字段 */
	private class ColumnNameTransfer implements Transfer<Object> {
		@Override
		public String transfer(final Object prop) {
			return columnNameStrategy.getColumnName(prop.toString());
		}
	}

	/** :prop --> 只是简单在前面加了一个冒号 */
	private class ColumnParamTransfer implements Transfer<Object> {
		@Override
		public String transfer(final Object prop) {
			return ":" + prop;
		}
	}

	/** column = :prop --> 生成update 语句中的设置部分, 其中column 是根据配置的字段规则进行转换的 */
	private class ColumnUpdateTransfer implements Transfer<Object> {
		@Override
		public String transfer(final Object prop) {
			final String column = columnNameStrategy.getColumnName(prop.toString());
			return column + " = :" + prop;
		}
	}
}
